(function($, undefined) {

var em = $.eventManager = {
	type: 'custom',
	debug: (typeof __debug != 'undefined') ?__debug : true,
	
	// Registers
	scriptRegister: new Array(),
	pluginsRegister: {},
	callBackInit: new Array(),
};

$.fn.eventManager = function(options) {
	var t = this;
	
	// Variables locals
	var defaults = {
		templates: {
			base: '<div class="em-content" />',
			error: '<div class="em-error" />'
		},
		messages: {
			errors: {
				eventEngine: { 	
					load: 			'<strong>Le moteur de chargement de l\'événement à planté !</strong>'+
									'<p>Impossible de charger le type d\'événement demandé</p>',
					parameters:		'<strong>Les paramètres reçus sont incorrects !</strong>'+
									'<p>Impossible de charger le type d\'événement demandé</p>'
				},
				pluginsEngine: {
					parameters:		'<strong>Les paramètres reçus sont incorrects !</strong>'+
									'<p>Impossible de charger le plugin</p>',
				},
				scriptLoader: 		'<strong>Le scriptLoader n\'a pas été défini !</strong>'+
									'<p>Impossible de charger les scripts pour le type d\'événement demandé</p>'
			}
		},
		heightMin: 400,
		initialize: true,
		render: true,

		plugins: {},
		cssLoader: [],
		scriptLoader: {},
		scriptDependancy: {}
	};
	
	// Ajout des paramètres spécifiques aux paramètres par defaut
	t.options = $.extend(true, {},
		defaults,
		options
	);
	
	// Variable public
	t.element = null;
	t.baseEvent = null;
	t.plugins = {};
	t.initialize = t.options.initialize;
	t.render = t.options.render;
	
	// Méthode public
	t.init = function(){ em.eventInit(t.baseEvent, t.options); t.onFinish(); };
	t.destroy = function(){ if(t.baseEvent) t.baseEvent.destroy(); };
	
	// Définition des events
	t.onStart = t.options.onStart || function(){};
	t.onFinish = t.options.onFinish || function(){};
	
	// Attribution du type d'event du manager
	em.type = t.options.type;
	
	this.each(function(i, _element) {
		t.element = $(_element);
		
		// Lancer l'event onStart
		t.onStart();
		
		t.baseEvent = new em.BaseEvent(t);
		t.element.data('eventManager', t);
		
		// Vérification du paramétrage
		if(typeof em.type == 'undefined'){
			baseEvent.errorMessage(t.options.messages.errors.eventEngine.parameters);
			return this;
		} else if(typeof t.options.scriptLoader == 'undefined'){
			baseEvent.errorMessage(t.options.messages.errors.scriptLoader);
			return this;
		}

		// Méthodes communes de fonction_core.js
		// Ajout des css et scripts définis dans les loader
		__dynamicCssLoad(t.options.cssLoader);
		
		var scriptLoaded = 0;
		var scriptLength = 0;
		$.each(t.options.scriptLoader, function(){ scriptLength++; });
		
		// Chargements scripts principaux
		__dynamicScriptLoad(t.options.scriptLoader, function(statut, name){
			if(statut == 200){
				em.addScriptToRegister(name);
			}
			scriptLoaded++;
			
			if(scriptLoaded == scriptLength){
				var scriptDepLoaded = 0;
				var scriptDepLength = 0;
				$.each(t.options.scriptDependancy, function(name, dependancies){
					if(em.isScriptRegistred(name))
						$.each(dependancies, function(){ scriptDepLength++; });
					else {
						console.log('Le script "'+name+'" n\'a pas été chargé. Les dépendences ne seront pas chargées');
						delete t.options.scriptDependancy[name];
					}						
				});
				
				if(scriptDepLength > 0){
					// Chargement des scripts dependant
					__dynamicScriptLoad(t.options.scriptDependancy, function(statut, name){
						if(statut == 200){
							em.addScriptToRegister(name);
						}
						scriptDepLoaded++;
	
						if(scriptDepLoaded == scriptDepLength && t.initialize){
							em.eventInit(t.baseEvent, t.options);
							t.onFinish();
						}
					});
				} else {
					if(t.initialize){
						em.eventInit(t.baseEvent, t.options);
						t.onFinish();
					}
				}
			}
		});
	});	
		
	return this;	
};

// Méthodes pour le registre des scripts chargés (scriptRegister)
em.addScriptToRegister = function(name){ if(!em.isScriptRegistred(name)) em.scriptRegister.push(name); };
em.isScriptRegistred = function(name){ return em.scriptRegister.indexOf(name) >= 0 ? true: false; };

// Méthodes pour le stockage des instances de plugins (pluginsRegister)
em.addPluginToRegister = function(pluginName, pluginInstance){ 
	if(!em.isRegestredPlugin(pluginName) && typeof pluginInstance != 'undefined'){ 
		em.pluginsRegister[pluginName] = pluginInstance;
	} else if(em.debug && em.isRegestredPlugin(pluginName)){
		console.log(pluginName+' est deja existant !!!');
	} else if(em.debug && typeof pluginInstance == 'undefined'){
		console.log(pluginName+' n\'a pas d\'instance valide executable !!!');
	}
};
em.isRegestredPlugin = function(name){ return typeof em.pluginsRegister[name] != 'undefined' ? true : false; };
em.getRegestredPlugin = function(name){ return em.pluginsRegister[name] != 'undefined' ? em.pluginsRegister[name] : null; };
em.removePluginFromRegister = function(name){ delete em.pluginsRegister[name]; };
em.checkPluginDependency = function(){};

em.addCallBackInit = function(callback){ em.callBackInit.push(callback); };

// Méthodes communes pour l'eventManager qui peuvent/doit être implémenter par l'event ou les plugins

/**
 * Méthode appelée à l'initialisation de l'event
 * @param eventBase Instance de gestion de base de l'event
 * @param options Options définies par l'eventManager
 */
em.eventInit = function(eventBase, options){ 
//	var scriptLength = 0;
//	$.each(options.scriptLoader, function(){ scriptLength++; });
//	
//	if(em.scriptRegister.length == scriptLength){
		eventBase.init();
//	} else
//		eventBase.errorMessage(options.messages.errors.eventEngine.load);
};

/**
 * Fonction appelée au moment d'un resize de l'event
 */
em.heightResize = function(){};

/**
 * Méthode pour lancer l'instance de l'event en fonction du type défini dans l'eventManager
 * La gestion des paramètres obligatoire doit être gérer spécifiquement pour chaque type d'event  
 * @param eventBase Instance de gestion de base de l'event
 * @param options Options définies par l'eventManager
 */
em.eventEngine = function(eventBase, options){ eventBase.errorMessage(options.messages.errors.eventEngine.load); return null; };


// Gestion de l'event

/**
 * Class BaseEvent est la class de gestion des events utilisés par l'eventManager
 * @param manager eventManager
 * @returns {em.BaseEvent}
 */
em.BaseEvent = function(manager) {
	var t = this;
	
	// Variables locals
	var _element = manager.element[0];
	var options = manager.options;
	var isInit = false;
		
	// exports
	t.event = null;
	t.content;
	t.plugins = [];
	
	t.init = init;
	t.destroy = destroy;
	t.errorMessage = errorMessage;
	
	// Initialisation de l'event
	function init(){
		// Initialisation du conteneur de base à faire AVANT l'initilisation de l'event		
		t.content = $(options.templates.base);
		
		// Récupération de l'event
		if(em.type != 'custom')
			t.event = em.eventEngine(t,options);
		
		// Récupération des plugins de l'event
		var tempEventPlugins = [];
		if(t.event && typeof t.event.plugins != 'undefined') tempEventPlugins = t.event.plugins;
		
		// Lancement du render avant le chargement des plugins !
		if(manager.render)
			render();

		// Vérification des plugins
		var tempPlugins = t.plugins.concat(manager.options.plugins, tempEventPlugins);
		$.each(tempPlugins, function(i, config){
			if(em.debug && typeof config.name == 'undefined')
				console.log('Un plugin sans nom n\'a pas pu être chargé');
			else if(typeof config.name != 'undefined' && em.isRegestredPlugin(config.name)){				
				t.plugins = t.plugins.concat([config]);
			} else if(em.debug)
				console.log('Le plugin "'+config.name+'" n\'existe pas dans le registre des plugins chargés');
		});

		// Initialisation des plugins
		$.each(t.plugins, function(i, config){
			var basePlugin = new em.BasePlugin(manager);
			basePlugin.init(em.pluginsRegister[config.name], config);
		});
		
		// Appel des callbacks
		$.each(em.callBackInit, function(i, callback){
			callback();
		});
	}
		
	function render() {
		if (!isInit) {
			initialRender();
		}

		if(t.event){
			try {
				t.event.render();
			} catch(e){
				if(em.debug) console.log(e);
			}
		}
		
		heightResize();
	}
	
	function initialRender() {			
		isInit = true;
		t.content.prependTo(_element);

		$(window).resize(windowResize);
	}	
	
	function destroy() {
		$(window).unbind('resize', windowResize);
		t.content.remove();
		t.content = null;
		isInit = false;
	}
		
	function heightResize() {
		var contentHeight = $(window).height() - $('body').outerHeight(true) + $(t.content).outerHeight(true);
		if(contentHeight > options.heightMin)
			$(t.content).height(contentHeight);
		else
			$(t.content).height(options.heightMin);
		
		// appel du height après implémentation par les events
		em.heightResize(t);
	}	
	
	function windowResize() {
		heightResize();
	}	
	
	function errorMessage(text, _options){
		if(typeof _options != 'undefined')
			options = _options;
		
		var errorContent = t.content;
		if(!errorContent)
			errorContent = _element;
		
		$(errorContent).html($(options.templates.error).html(text));
	}
};

/**
 * Class BasePlugin est la classe de gestion des plugins utilisés par l'eventManager
 * @param manager eventManager
 * @returns {em.BasePlugin}
 */
em.BasePlugin = function(manager){
	var t = this;
	
	// Variables locals
	var event = manager.baseEvent;
	var name;
	var settings = {};
	var defaults = {
		data: {},
		options: manager.options.plugins,
		dependency: {}
	};
	
	// exports
	t.plugin;
	
	t.init = init;
	t.destroy = destroy;
	t.errorMessage = errorMessage;
	
	// Initialisation du plugin
	function init(plugin, config){
		settings = $.extend(true, {}, defaults, config);
		name = settings.name;
		
		try{
			if(typeof settings.element != 'undefined' && $(settings.element).size() != 0){
				var instancePlugin = new plugin(settings);
				manager.plugins[name] = instancePlugin;
				t.plugin = instancePlugin;
			} else if(em.debug && typeof settings.element == 'undefined')
				console.log('L\'attribut "element" du plugin "'+name+'" doit obligatoirement être renseigné');
			else if(em.debug && $(settings.element).size() == 0)
				console.log('L\'élément "'+settings.element+'" du plugin "'+name+'" doit être existant');
		} catch(e) {
			if(em.debug) console.log(e);
		}
		
		//if(t.plugin && manager.render)
		//	t.plugin.render();
	}
	
	function destroy(){
		$(t.plugin.element).remove();
	}
	
	function errorMessage(){
		
	}
};

})(jQuery);